import { сodesSizesDescription } from 'constatnts';
import { IncomingParserResult } from 'store';

class IncomingParser {
  ptr = 0;
  cmdCode = 0;
  channelNumber = 0;
  sequenceNumber = 0;
  uint8T: number[] = [];

  prepareWith (uint8T: number[]) {
    this.ptr = 0;
    this.uint8T = uint8T;
  }

  parse (): IncomingParserResult | null {
    return this.stage01ChannelNumber();
  }

  stage01ChannelNumber (): IncomingParserResult | null {
    if (!this.isSufficientAmount()) {
      return null;
    }

    this.channelNumber = this.uint8T[this.ptr];
    this.ptr++;

    return this.stage02CmdCode();
  }

  stage02CmdCode (): IncomingParserResult | null {
    if (!this.isSufficientAmount()) {
      return null;
    }

    this.cmdCode = this.uint8T[this.ptr];

    if (!this.isAllowedCmdCode()) {
      return null;
    }

    this.ptr++;

    return this.stage03Sequence();
  }

  stage03Sequence (): IncomingParserResult | null {
    if (!this.isSufficientAmount(2)) {
      return null;
    }

    this.sequenceNumber = (this.uint8T[this.ptr] >> 8) + this.uint8T[this.ptr + 1];

    this.ptr += 2;

    return this.stage04StandardFinal();
  }

  stage04StandardFinal (): IncomingParserResult | null {
    const csd = сodesSizesDescription.find(
      ({ cmdCode }) => cmdCode === this.cmdCode
    )

    if (!csd || !this.isSufficientAmount(csd.valueSize)) {
        return null;
    }

    const uint8T =
      !csd.valueSize ?
      [] :
      this.uint8T.slice(this.ptr, this.ptr + csd.valueSize);

    const result: IncomingParserResult = {
      channelNumber: this.channelNumber,
      cmdCode: this.cmdCode,
      sequenceNumber: this.sequenceNumber,
      uint8T,
    };

    this.ptr += csd.valueSize;

    return result;
  }

  isAllowedCmdCode (): boolean {
    return Boolean(
      сodesSizesDescription.find(
        ({ cmdCode }) => cmdCode === this.cmdCode
      )
    );
  }

  isSufficientAmount (amount: number = 1): boolean {
    return Boolean(
      this.uint8T?.length && ((this.ptr + amount) <= this.uint8T.length)
    );
  }
};

export default IncomingParser;
